package com.hhl.lamda.streamcollectorsgroupingby;

import com.hhl.lamda.entity.Item;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HHL
 * @description
 * @date 2018/11/18 - 13:46
 */
public class StreamCollectorsGroupingBy {

    public static void main(String[] args) {

        //3 apple, 2 banana, others 1
        List<String> items =
                Arrays.asList("apple", "apple", "banana",
                        "apple", "orange", "banana", "papaya");

        // Function.identity()返回一个输出跟输入一样的Lambda表达式对象，相当于循环到的对象本身，等价于形如t -> t形式的Lambda表达式
        Map<String, Long> result = items.stream()  // 将list类型的items转化为stream
                .collect(Collectors.groupingBy(
                      Function.identity(), Collectors.counting()
                ));
        System.out.println(result);  // papaya=1, orange=1, banana=2, apple=3






        // Add sorting
        // Function.identity()返回一个输出跟输入一样的Lambda表达式对象，相当于循环到的对象本身，等价于形如t -> t形式的Lambda表达式
        Map<String, Long> result1 = items.stream()
                .collect(Collectors.groupingBy(
                        Function.identity(), Collectors.counting()
                ));

        Map<String, Long> finalMap = new LinkedHashMap<>();


        //Sort a map and add to finalMap
//        keySet是键的集合，Set里面的类型即key的类型
//        entrySet是 键-值 对的集合，Set里面的类型是Map.Entry
        result1.entrySet().stream()  // 将 entrySet 键-值 对的集合 转化为 Stream
                .sorted(Map.Entry.<String, Long>comparingByValue() // entrySet里面的类型  Map.Entry 按 value 值排序（long类型，按数字大小排序）
                .reversed())  // 将排序结果逆序排列
                .forEachOrdered(  // 将逆序排列结果 按顺序 put 进 finalMap
                        e -> finalMap.put(e.getKey(), e.getValue())
                );
        // apple=3, banana=2, papaya=1, orange=1
        System.out.println(finalMap);





        //3 apple, 2 banana, others 1
        List<Item> itemsList = Arrays.asList(
                new Item("apple", 10, new BigDecimal("9.99")),
                new Item("banana", 20, new BigDecimal("19.99")),
                new Item("orang", 10, new BigDecimal("29.99")),
                new Item("watermelon", 10, new BigDecimal("29.99")),
                new Item("papaya", 20, new BigDecimal("9.99")),
                new Item("apple", 10, new BigDecimal("9.99")),
                new Item("banana", 10, new BigDecimal("19.99")),
                new Item("apple", 20, new BigDecimal("9.99"))
        );




        //  按名字分组
        Map<String, Long> counting = itemsList.stream()
                .collect(
                        Collectors.groupingBy(
                                Item::getName, // 按名字分组 并统计每组的记录数
                                Collectors.counting()));
        // papaya=1, banana=2, apple=3, orang=1, watermelon=1
        System.out.println(counting);




        Map<String, Integer> sum = itemsList.stream().collect(
                Collectors.groupingBy(Item::getName, // 按名字分组 并 按该组的qty求和
                        Collectors.summingInt(Item::getQty))
        );
        // papaya=20, banana=30, apple=40, orang=10, watermelon=10
        System.out.println(sum);




        //group by price
        Map<BigDecimal, List<Item>> groupByPriceMap =
                itemsList.stream()
                        .collect(Collectors.groupingBy(Item::getPrice));  // 按价格分组
        System.out.println(groupByPriceMap);
//        {
//            19.99=[
//            Item{name='banana', qty=20, price=19.99},
//            Item{name='banana', qty=10, price=19.99}
//		],
//            29.99=[
//            Item{name='orang', qty=10, price=29.99},
//            Item{name='watermelon', qty=10, price=29.99}
//		],
//            9.99=[
//            Item{name='apple', qty=10, price=9.99},
//            Item{name='papaya', qty=20, price=9.99},
//            Item{name='apple', qty=10, price=9.99},
//            Item{name='apple', qty=20, price=9.99}
//		]
//        }





        // group by price, uses 'mapping' to convert List<Item> to Set<String>
        Map<BigDecimal, Set<String>> result2 =
                itemsList.stream()
                .collect(
                        Collectors.groupingBy(Item::getPrice, // 按价格分组
                                Collectors.mapping(Item::getName, // 将每组价格对应的水果名字取出 并转化为 set
                                        Collectors.toSet()))
                );
        System.out.println(result2);
        //group by + mapping to Set
//        {
//            19.99=[banana],
//            29.99=[orang, watermelon],
//            9.99=[papaya, apple]
//        }














    }
}
